#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>

#define PORT 8888
#define SERVER_IP "192.168.152.130"
#define BUFFER_SIZE 128

//自定义结构体 -> 封装客户端连接信息，用于再线程间传递
typedef struct struct_MSG {
    int acceptfd;//客户端连接套接字
    struct sockaddr_in client_addr;//客户端地址结构体
}msg_t;

//线程处理函数
void *deal_read_write(void *arg){
    msg_t msg = *(msg_t *)arg;
    char buffer[BUFFER_SIZE] = {0};
    int nbytes = 0;
    printf("客户端【%s:%d】连接到服务器\n",inet_ntoa(msg.client_addr.sin_addr), ntohs(msg.client_addr.sin_port));

    //客户端数据接收与发送
    while (1){
        nbytes = recv(msg.acceptfd, buffer, BUFFER_SIZE, 0);
        if (nbytes == -1){
            perror("读取客户端消息失败：");
        }else if (nbytes == 0){
            printf("客户端【%s:%d】断开连接\n",inet_ntoa(msg.client_addr.sin_addr), ntohs(msg.client_addr.sin_port));
            break;
        }
        printf("客户端【%s:%d】发送消息：%s\n",inet_ntoa(msg.client_addr.sin_addr), ntohs(msg.client_addr.sin_port), buffer);

        //回显消息给客户端
        strcat(buffer, "--服务器回显");
        if (send(msg.acceptfd, buffer, strlen(buffer), 0) == -1){
            perror("回显消息失败：");
        }
    }
    close(msg.acceptfd);
    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{
    //创建套接字--配置服务器地址结构体
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1){
        perror("socket创建失败：");
        return -1;
    }

    //绑定套接字
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    socklen_t serveraddr_len = sizeof(server_addr);

    int on = 1;
    //设置套接字选项，允许地址重用
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

    //绑定、监听、处理客户端的连接
    if (bind(sockfd, (struct sockaddr *)&server_addr, serveraddr_len) == -1){
        perror("bind失败：");
        close(sockfd);
        return -1;
    }

    if (listen(sockfd, 5) == -1){
        perror("监听失败：");
        close(sockfd);
        return -1;
    }

    struct sockaddr_in client_addr;
    socklen_t clientaddr_len = sizeof(client_addr);

    int acceptfd = 0;
    pthread_t tid = 0;
    msg_t msg;
    int ret = 0;

    //主线程：接受连接并创建子线程
    while (1){
        if( (acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &clientaddr_len)) == -1){
            perror("接受连接失败：");
            return -1;
        }

        msg.acceptfd = acceptfd;
        msg.client_addr = client_addr;

        //创建子线程
        ret = pthread_create(&tid, NULL, deal_read_write, (void *)&msg);
        if (ret == -1){
            printf("错误码：%d，错误信息：%s\n",ret, strerror(ret));
            close(sockfd);
            return -1;
        }

        ret = pthread_detach(tid);
        if (ret == -1){
            printf("错误码：%d，错误信息：%s\n",ret, strerror(ret));
            close(sockfd);
            return -1;
        }
    }

    close(sockfd);
    return 0;
}
